package com.situ.shoplook.common.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheKey;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.util.function.Supplier;

/**
 * 功能：
 *
 * @author 千堆雪
 * @version 1.0.0
 * <p>
 * created by 千堆雪 on 2024/8/24, last modified by 千堆雪 on 2024/8/24
 */
public class RedisCache implements Cache {
    private final String id;
    private final Supplier<RedisTemplate<String, Object>> redisTemplateSupplier;

    public RedisCache(String id) {
        this.id = id;
        this.redisTemplateSupplier = RedisTemplateHolder::getRedisTemplate;
    }

    @Override
    public String getId() {
        return this.id;
    }

    private RedisTemplate<String, Object> getRedisTemplate() {
        return this.redisTemplateSupplier.get();
    }

    @Override
    public void putObject(Object key, Object value) {
        getRedisTemplate().opsForHash().put(getId(), jsonKey((CacheKey) key), value);
    }

    @Override
    public Object getObject(Object key) {
        return getRedisTemplate().opsForHash().get(getId(), jsonKey((CacheKey) key));
    }

    @Override
    public Object removeObject(Object key) {
        return getRedisTemplate().opsForHash().delete(getId(), jsonKey((CacheKey) key));
    }

    @Override
    public void clear() {
        getRedisTemplate().delete(getId());
    }

    @Override
    public int getSize() {
        return getRedisTemplate().opsForHash().size(getId()).intValue();
    }

    private static String jsonKey(CacheKey cacheKey) {
        return cacheKey.toString();
    }

    private static class RedisTemplateHolder {
        private static RedisTemplate<String, Object> getRedisTemplate() {
            RedisConnectionFactory rc = SpringUtils.getBean(RedisConnectionFactory.class);
            ObjectMapper om = SpringUtils.getBean(ObjectMapper.class);

            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(rc);

            RedisSerializer<String> stringSerializer = RedisSerializer.string();
            RedisSerializer<Object> valueSerializer = GenericJackson2JsonRedisSerializer.builder()
                    .objectMapper(om.copy()).defaultTyping(true).build();

            redisTemplate.setKeySerializer(stringSerializer);
            //key需要使用字符串序列化器，如果使用json序列化器，反而会出现问题
            redisTemplate.setHashKeySerializer(stringSerializer);
            redisTemplate.setHashValueSerializer(valueSerializer);

            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    }
}
